package util;

import constantClass.Constant;
import information.Information;
import intercept.HandlerExecutionChain;
import util.handfactoryimp.HandFactoryImp;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;

/**
 * 中央控制器，通过url路径分发访问的Hanlder
 */
public class Instantiation extends HttpServlet{

    /**
     * Tomcat, Jetty, JBoss, GlassFish 默认Servlet名称
     * 如果是静态资源或者是控制器无法处理的请求，则交给容器的默认Servlet处理
     */
    private static final String COMMON_DEFAULT_SERVLET_NAME = "default";
    /**
     * 从xml文件容器中获取的默认Servlet名为defaultServletName值
     */
    String defaultServletName;

    /**
     * 初始化map
     * @param config
     * @throws ServletException
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        //初始化ioc mvc注入方式
        initFactory(config);
        //初始化存放调用方法和class的map集合
        initMap(config);
        //初始化web.xml容器的值
        initDefaultServlet(config);
    }

    /**
     * 初始化web容器的默认Servlet名称
     *
     * @param config
     */
    private void initDefaultServlet(ServletConfig config) {
        ServletContext servletContext = config.getServletContext();//获取上下文对象
        defaultServletName = servletContext
                .getInitParameter("defaultServletName");//从xml文档里获取defaultServletName，给用于自定义默认处理方式，可以不打
        if (defaultServletName == null || "".equals(defaultServletName)) {//如果等于null，证明用户没有自定义处理方式，所以我们要定义一个默认的处理方式
            if (servletContext.getNamedDispatcher(COMMON_DEFAULT_SERVLET_NAME) != null) {//从上下文对象中找是否有这个default的默认处理方式，一定是defalut
                defaultServletName = COMMON_DEFAULT_SERVLET_NAME;//给默认的处理方式赋值->defalut
            } else {
                throw new IllegalStateException("Unable to locate the default servlet for serving static content. " +
                        "Please set the 'defaultServletName' property explicitly.");
            }
        }
    }

    /**
     * 当请求匹配不到相应的映射描述, 则给容器默认的servlet处理
     *
     * @throws IOException
     * @throws ServletException
     */
    protected void forwardDefaultServlet(HttpServletRequest request,
                                         HttpServletResponse response) throws ServletException, IOException {
        RequestDispatcher rd = request.getServletContext().getNamedDispatcher(
                defaultServletName);//从上下文对象中找到default这个转发类
        if (rd == null) {
            throw new IllegalStateException(
                    "A RequestDispatcher could not be located for the default servlet '"
                            + this.defaultServletName + "'");
        }
        rd.forward(request, response);//跳转页面
    }

    /**
     * 注入对象方式
     * @param config
     */
    private void initFactory(ServletConfig config) {
        if(config.getServletContext().getAttribute(Constant.FACTORY)==null){
            System.out.println("mvc自行注入");
            config.getServletContext().setAttribute(Constant.FACTORY,new HandFactoryImp());
        }else{
            System.out.println("启动插件，ioc注入");
        }
    }

    /**
     * 入口方法   思路  目的：调用方法  思考：通过反射调用方法需要什么？
     * 1.获取存放的所有方法的map集合
     * 2.通过地址链接的一段字符对应map的一个键值，从而得到一个对应的方法和这个方法所在类的实例
     * 3.然后获取这个方法的所有参数值
     * 4.最后调用方法
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */

    /**
     * 笔记
     * servlet处理静态资源d
     */

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //得到map的键值
        String url = subServiceInit(req);
        //初始化HttpFactory
        initHttpFactory(req,resp);
        //得到map
        Map<String, Information> map = (Map<String, Information>) (req.getServletContext().getAttribute(Constant.MAP));
        if(map.get(url)==null) {
            forwardDefaultServlet(req,resp);
        }else{
            //传给责任链调用方法
            HandlerExecutionChain.getHandlerExecutionChain().setInformation(map.get(url));
            HandlerExecutionChain.getHandlerExecutionChain().handler();
        }
    }

    private void initMap(ServletConfig config){
        Map<String, Information> map = InitMap.getMap();
        //放到上下文变量
        config.getServletContext().setAttribute(Constant.MAP,map);
    }
    /**
     * 初始化HttpFactory
     * @param req
     * @param resp
     */
    private static void initHttpFactory(HttpServletRequest req, HttpServletResponse resp){
        HttpFactory hf = HttpFactory.getActionFaction();
        hf.setResponse(resp);
        hf.setRequest(req);
    }

    /**
     * 截取链接地址的字段
     * @param req
     * @return
     */
    private String subServiceInit(HttpServletRequest req){
        //接收到网址的最后的带/的字符串
        String str = req.getServletPath();
        //去掉/得到map键值
        String strServlet = str.replace("/", "");
        return strServlet;
    }
}
